/**
 * EQ Chart Module - 用于绘制均衡器曲线的可视化组件
 * @module EqChart
 */
import { chManager } from './defaultconfig.js';
import { EqChartMask } from './eq_chart_mask.js';
import { CHPass, CHSign, EqTool, } from './eq_tool.js';
import { EQUtil } from './eq_util.js';
/**. 
 * EQ图表类，用于创建和渲染均衡器曲线
 */
export class EqChart {
    /**
     * 构造函数
     * @param {string} containerId - 容器元素的ID
     * @param {Object} options - 配置选项
     * @param {string} options.backgroundColor - 背景颜色
     * @param {string} options.gridColor - 网格线颜色
     * @param {string} options.textColor - 文本颜色
     */
    constructor(containerId, {
        backgroundColor = '#1C1C1E',
        gridColor = '#3A3A3C',
        textColor = '#C7C7CC',
        onChange = null,
        delay = 30
    } = {}) {
        this.containerId = containerId;
        this.logicalWidth = 0;  // 画布逻辑宽度
        this.logicalHeight = 0; // 画布逻辑高度
        this.points = [];       // 频率点对应的x轴坐标
        this.freq_list = chManager.config.freqList; // 频率列表
        this.backgroundColor = backgroundColor;
        this.gridColor = gridColor;
        this.textColor = textColor;

        this.onChange = onChange || null;
        this.delay = delay;///默认30毫秒

        this.init(); // 初始化图表
    }

    /**
     * 初始化图表
     */
    init() {
        this.createDOM();       // 创建DOM结构
        this.setupCanvas();     // 设置画布
        this.createMask();
        this.addxAxisLabel();   // 添加x轴标签
        this.resizeAndDraw();   // 调整大小并绘制
        this.bindEvents();      // 绑定事件
    }

    /**
     * 创建DOM结构
     */
    createDOM() {
        const container = document.getElementById(this.containerId);

        // 清空
        container.innerHTML = "";

        // bg_container
        const bgContainer = document.createElement("div");
        bgContainer.id = "bg_container";
        bgContainer.style.margin = "0";
        bgContainer.style.padding = "0";
        bgContainer.style.width = "100%";
        bgContainer.style.height = "100%";
        bgContainer.style.border = "none";
        bgContainer.style.background = "transparent";
        bgContainer.style.boxSizing = "border-box";
        bgContainer.style.display = "flex";
        bgContainer.style.flexDirection = "row";
        bgContainer.style.paddingTop = "5px";
        bgContainer.style.paddingRight = "5px";

        // my_db_yaxis
        const myDbYaxis = document.createElement("div");
        myDbYaxis.id = "my_db_yaxis";
        myDbYaxis.style.width = "60px";
        myDbYaxis.style.height = "calc(100% - 30px)";
        myDbYaxis.style.background = "transparent";
        myDbYaxis.style.boxSizing = "border-box";
        myDbYaxis.style.display = "flex";
        myDbYaxis.style.flexDirection = "column";
        myDbYaxis.style.justifyContent = "space-between";

        const dbTemplate = document.createElement("template");
        dbTemplate.className = "db_yaxis_template";
        const span1 = document.createElement("span");
        dbTemplate.content.appendChild(span1);
        myDbYaxis.appendChild(dbTemplate);

        // bg_chart
        const bgChart = document.createElement("div");
        bgChart.id = "bg_chart";
        bgChart.style.flexGrow = "1";
        bgChart.style.height = "100%";
        bgChart.style.padding = "0";
        bgChart.style.boxSizing = "border-box";
        bgChart.style.display = "flex";
        bgChart.style.flexDirection = "column";
        bgChart.style.background = "transparent";

        // my_chart
        this.myChart = document.createElement("div");
        this.myChart.id = "my_chart";
        this.myChart.style.width = "100%";
        this.myChart.style.height = "calc(100% - 30px)";
        this.myChart.style.display = "block";
        this.myChart.style.background = "transparent";
        this.myChart.style.border = "none";
        this.myChart.style.boxSizing = "border-box";
        this.myChart.style.position = "relative";

        // bg_canvas
        const bgCanvas = document.createElement("canvas");
        bgCanvas.id = "bg_canvas";
        bgCanvas.style.position = "absolute";
        bgCanvas.style.top = "0";
        bgCanvas.style.left = "0";
        bgCanvas.style.height = "100%";
        bgCanvas.style.border = "none";
        bgCanvas.style.padding = "0";
        bgCanvas.style.margin = "0";
        bgCanvas.style.minWidth = "0px";
        bgCanvas.style.minHeight = "0px";
        bgCanvas.style.boxSizing = "border-box";
        bgCanvas.style.background = this.backgroundColor;
        bgCanvas.style.zIndex = "0";

        // canvas_line
        const canvasLine = document.createElement("canvas");
        canvasLine.id = "canvas_line";
        canvasLine.style.position = "absolute";
        canvasLine.style.top = "0";
        canvasLine.style.left = "0";
        canvasLine.style.height = "100%";
        canvasLine.style.border = "none";
        canvasLine.style.padding = "0";
        canvasLine.style.margin = "0";
        canvasLine.style.minWidth = "0px";
        canvasLine.style.minHeight = "0px";
        canvasLine.style.boxSizing = "border-box";
        canvasLine.style.background = "transparent";
        canvasLine.style.zIndex = "1";

        this.myChart.appendChild(bgCanvas);
        this.myChart.appendChild(canvasLine);

        // my_freq_xaxis
        const myFreqXaxis = document.createElement("div");
        myFreqXaxis.id = "my_freq_xaxis";
        myFreqXaxis.style.width = "100%";
        myFreqXaxis.style.height = "30px";
        myFreqXaxis.style.margin = "0";
        myFreqXaxis.style.boxSizing = "border-box";
        myFreqXaxis.style.position = "relative";

        const freqTemplate = document.createElement("template");
        freqTemplate.className = "freq_xaxis_template";
        const span2 = document.createElement("span");
        span2.style.color = this.textColor;
        freqTemplate.content.appendChild(span2);
        myFreqXaxis.appendChild(freqTemplate);

        // 装配
        bgChart.appendChild(this.myChart);
        bgChart.appendChild(myFreqXaxis);

        bgContainer.appendChild(myDbYaxis);
        bgContainer.appendChild(bgChart);

        container.appendChild(bgContainer);

        // this.ball3d = new EqBall3D('my_chart');
    }

    ///添加遮罩
    createMask() {
        this.points = this.freq_list.map(($0) => Math.round(EQUtil.toInt($0, this.myChart.clientWidth)));
        this.maskLayer = new EqChartMask(this.myChart.id, this.points, {
            delay: this.delay, onChange: () => {
                this.updateChart();
                this.onChange();
            }
        });
    }
    /**
     * 设置画布
     */
    setupCanvas() {
        this.bg_canvas = document.getElementById("bg_canvas");
        this.bg_ctx = this.bg_canvas.getContext("2d");
        this.line_canvas = document.getElementById("canvas_line");
        this.line_ctx = this.line_canvas.getContext("2d");
    }

    /**
     * 调整大小并重新绘制
     */
    resizeAndDraw() {
        const parent = document.getElementById('bg_container');
        const dpr = devicePixelRatio || 1;

        this.logicalWidth = this.myChart.clientWidth;
        this.logicalHeight = this.myChart.clientHeight;
        this.points = this.freq_list.map(($0) => Math.round(EQUtil.toInt($0, this.logicalWidth)));

        this.setupCanvasSize(this.bg_canvas, this.bg_ctx);
        this.setupCanvasSize(this.line_canvas, this.line_ctx);
        this.drawWaveform(this.logicalWidth, this.logicalHeight);
    }

    /**
     * 设置画布大小
     * @param {HTMLCanvasElement} canvas - 画布元素
     * @param {CanvasRenderingContext2D} ctx - 画布上下文
     */
    setupCanvasSize(canvas, ctx) {
        const dpr = devicePixelRatio || 1;
        canvas.width = this.logicalWidth * dpr;
        canvas.height = this.logicalHeight * dpr;
        canvas.style.width = this.logicalWidth + 'px';
        canvas.style.height = this.logicalHeight + 'px';

        ctx.setTransform(1, 0, 0, 1, 0, 0);
        ctx.scale(dpr, dpr);
    }

    /**
     * 绘制波形
     * @param {number} width - 画布宽度
     * @param {number} height - 画布高度
     */
    drawWaveform(width, height) {
        this.bg_ctx.clearRect(0, 0, width, height);
        this.line_ctx.clearRect(0, 0, width, height);

        this.drawXaxis(width, height, 4, this.gridColor); // 绘制x轴网格
        this.drawYaxis(width, height, 10, this.gridColor); // 绘制y轴网格
        this.addyAxisLabel(); // 添加y轴标签
        this.maskLayer.refreshUI();
        this.drawEqLine(); // 绘制EQ曲线
    }

    /**
     * 绘制x轴网格
     * @param {number} w - 宽度
     * @param {number} h - 高度
     * @param {number} n - 分割数
     * @param {string} color - 颜色
     */
    drawXaxis(w, h, n, color) {
        const gap = h / n;
        for (let i = 1; i < n; i++) {
            this.bg_ctx.beginPath();
            this.bg_ctx.moveTo(0, gap * i);
            this.bg_ctx.lineTo(w, gap * i);
            this.bg_ctx.strokeStyle = color;
            this.bg_ctx.stroke();
        }
    }

    /**
     * 绘制y轴网格
     * @param {number} w - 宽度
     * @param {number} h - 高度
     * @param {number} n - 分割数
     * @param {string} color - 颜色
     */
    drawYaxis(w, h, n, color) {
        // this.ball3d.clear();
        this.points.forEach((x, i) => {
            this.bg_ctx.beginPath();
            this.bg_ctx.moveTo(x, 0);
            this.bg_ctx.lineTo(x, h);
            this.bg_ctx.strokeStyle = color;
            this.bg_ctx.stroke();
            // this.ball3d.draw(x, h / 2);
            // this.ball3d.drawText(`${i}`);
        });
    }

    /**
     * 绘制EQ曲线
     */
    drawEqLine() {
        if (!chManager || !EqTool || !EQUtil) {
            console.error('错误：Required dependencies not available');
            return;
        }

        // 获取当前通道的EQ配置
        const ch = chManager.current_chlist[0];

        const sign_list = ch.sign_list.map(($0) => new CHSign($0.q, $0.gain, $0.freq));
        const sign = ch.sign_list[0];
        const high = new CHPass(ch.high_pass.freq, ch.high_pass.type.oct_type, true, false);
        const low = new CHPass(ch.low_pass.freq, ch.low_pass.type.oct_type, false, false);
        const current_freq_list = ch.sign_list.map(($0) => Math.round(EQUtil.toInt($0.freq, this.logicalWidth)));

        // 计算EQ曲线数据
        const list = EqTool.eqTotal(
            sign_list,
            high,
            low,
            { width: this.logicalWidth, height: this.logicalHeight },
            (sign.max_gain - sign.min_gain) / 2,
            0.5555556 * 25
        );
        this.line_ctx.clearRect(0, 0, this.logicalWidth, this.logicalHeight);

        const rect_canvas = this.line_canvas.getBoundingClientRect();
        // 绘制曲线
        this.line_ctx.beginPath();
        this.line_ctx.moveTo(-1, this.logicalHeight / 2 + list[0]);
        list.forEach((p, i) => {
            const m = this.realHeight(p);
            this.line_ctx.lineTo(i == 0 ? -1 : i, m);
            ///更新数字点
            if (current_freq_list.includes(i)) {
                const matchedIndex = current_freq_list.findIndex(el => el === i);
                this.maskLayer.updatePosition(matchedIndex, i + rect_canvas.left, m + rect_canvas.top);
            }
        });
        this.line_ctx.strokeStyle = ch.hex_line;
        this.line_ctx.stroke();

        // 绘制渐变填充
        this.line_ctx.beginPath();
        this.line_ctx.moveTo(-1, this.logicalHeight);
        list.forEach((p, i) => {
            const m = this.realHeight(p);
            this.line_ctx.lineTo(i == 0 ? -1 : i, m);
        });
        this.line_ctx.lineTo(this.logicalWidth, this.logicalHeight);
        this.line_ctx.lineTo(0, this.logicalHeight);
        this.line_ctx.closePath();

        const gradient = this.line_ctx.createLinearGradient(0, this.logicalHeight / 2, 0, this.logicalHeight);
        gradient.addColorStop(0, `${ch.hex_line}` + `${parseInt(sign.max_gain)}`);
        gradient.addColorStop(1, `${ch.hex_line}01`);
        this.line_ctx.fillStyle = gradient;
        this.line_ctx.fill();
    }

    /**
     * 将增益值转换为实际高度
     * @param {number} y - 增益值
     * @returns {number} 实际高度
     */
    realHeight(y) {
        const scale = this.logicalHeight / (chManager.config.max_gain - chManager.config.min_gain);
        return (chManager.config.max_gain - y) * scale;
    }

    /**
     * 添加x轴标签（dB刻度）
     */
    addxAxisLabel() {
        const db_yaxis = document.getElementById('my_db_yaxis');
        const db_template = document.querySelector('.db_yaxis_template');
        const list = [chManager.config.max_gain, chManager.config.max_gain / 2, 0, chManager.config.min_gain / 2, chManager.config.min_gain];

        list.forEach((item) => {
            const clone = db_template.content.cloneNode(true);
            const span = clone.querySelector('span');
            span.textContent = `${item}` + (item == 0 ? "dB" : "");
            db_yaxis.appendChild(span);
        });
    }

    /**
     * 添加y轴标签（频率刻度）
     */
    addyAxisLabel() {
        const db_yaxis = document.getElementById('my_freq_xaxis');
        const db_template = document.querySelector('.freq_xaxis_template');

        document.querySelectorAll('#bg_chart span').forEach(item => item.remove());

        this.freq_list.forEach((item, index) => {
            const freq = item >= 1000 ? `${Math.floor(item / 1000 * 10) / 10}k` : `${item}`;
            const clone = db_template.content.cloneNode(true);
            const span = clone.querySelector('span');
            span.style.position = 'absolute';
            span.style.left = `${this.points[index]}px`;
            span.style.transform = index === this.freq_list.length - 1 ? 'translateX(-100%)' : 'translateX(-50%)';
            span.textContent = freq;
            db_yaxis.appendChild(span);
        });
    }

    /**
     * 绑定事件
     */
    bindEvents() {
        this.resizeHandler = () => {
            if (this.resizeTimer) cancelAnimationFrame(this.resizeTimer);
            this.resizeTimer = requestAnimationFrame(() => this.resizeAndDraw());
        };
        addEventListener('resize', this.resizeHandler);
    }

    /**
     * 更新图表
     */
    updateChart() {
        this.drawEqLine();
    }

    /**
     * 设置数据
     * @param {Object} chManagerData - 通道管理数据
     */
    setData(chManagerData) {
        chManager = chManagerData;
        this.updateChart();
    }

    /**
     * 销毁图表
     */
    destroy() {
        removeEventListener('resize', this.resizeHandler);
        if (this.resizeTimer) {
            cancelAnimationFrame(this.resizeTimer);
        }
        document.getElementById(this.containerId).innerHTML = '';
    }
}
